﻿//======================================================================
//
//	Cross-Platform XNA Menu System
//  http://cpxms.codeplex.com/
//
//  All code and content licensed under Microsoft Public License (Ms-PL)	
//
//======================================================================
//
//	File:		Button.cs
//
//	Author:		MJP
//
//	Date:		04/19/09
//
//======================================================================

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Xml.Serialization;
using System.Drawing.Design;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace CPXMenu
{
	/// <summary>
	/// An item that responds to user input, and can be used to trigger page flips.
	/// </summary>
    [Description("An item that responds to user input, and can be used to trigger page flips.")]
    [CanHaveChildren(false)]
    [IconKey("Button")]
    [Selectable(true)]
    [Movable(true)]
    [Sizeable(true)]
    [CanCopyPaste(true)]
    [CanHaveFocus(true)]
    public class Button : MenuItem
    {
        private ImageState idleImageState = new ImageState();
        private ImageState focusedImageState = new ImageState();
        private ImageState pressedImageState = new ImageState();
        private TextState textState = new TextState();
        private ButtonDesignState designState = ButtonDesignState.Idle;

        private PageFlipType pageFlipType = PageFlipType.None;
        private PageFlipEffect pageFlipEffect = new InstantPageFlipEffect();
        private Page pageFlipTarget = null;
        private ulong pageFlipTargetID = 0;

		public const string DefaultIdleImage = "CPXMenu Content\\Textures\\ButtonIdle";
        public const string DefaultFocusedImage = "CPXMenu Content\\Textures\\ButtonFocused";
        public const string DefaultPressedImage = "CPXMenu Content\\Textures\\ButtonPressed";
		public const string DefaultFont = "CPXMenu Content\\Fonts\\ArialS";        

		/// <summary>
		/// Gets or sets the ImageState representing the Button's appearance when idle
		/// </summary>
        [Browsable(true)]
		[Category("Appearance")]
        [Description("The appearance of the button when it's in the idle state")]
        public ImageState IdleImageState
        {
            get { return idleImageState; }
            set
            {
                idleImageState = value;
                SetImageStates();
            }
        }

		/// <summary>
		/// Gets or sets the ImageState representing the Button's appearance when focused
		/// </summary>
        [Browsable(true)]
		[Category("Appearance")]
        [Description("The appearance of the button when it's in the focused state")]
        public ImageState FocusedImageState
        {
            get { return focusedImageState; }
            set
            {
                focusedImageState = value;
                SetImageStates();
            }
        }

		/// <summary>
		/// Gets or sets the ImageState representing the Button's appearance when pressed
		/// </summary>
        [Browsable(true)]
		[Category("Appearance")]
        [Description("The appearance of the button when it's in the pressed state")]
        public ImageState PressedImageState
        {
            get { return pressedImageState; }
            set
            {
                pressedImageState = value;
                SetImageStates();
            }
        }

        /// <summary>
        /// Gets or sets the TextState representing the Button's appearance 
		/// </summary>
        [Browsable(true)]
        [Category("Text")]
        [Description("The text drawn on the button")]
        public TextState TextState
        {
            get { return textState; }
            set
            {
                textState = value;
                SetTextStates();
            }
        }		

		/// <summary>
		/// Gets or sets a value indicating which state should be drawn when in design mode
		/// </summary>
        [Browsable(true)]
        [Category("Design")]
        [Description("The state of the button in design mode")]
        [XmlIgnore]
        public ButtonDesignState DesignState
        {
            get { return designState; }
            set { designState = value; }
        }

        /// <summary>
        /// Gets or sets the type of page flip assigned to the button
        /// </summary>
        [Browsable(true)]
        [Category("Page Flip")]
        [Description("The type of Page Flip to assign to the button")]       
        public PageFlipType PageFlipType
        {
            get { return pageFlipType; }
            set
            {
                pageFlipType = value;
                if (pageFlipType == PageFlipType.None || pageFlipType == PageFlipType.Return)
                {
                    pageFlipTarget = null;
                    pageFlipTargetID = 0;
                }
            }
        }

        /// <summary>
        /// Gets or sets the visual effect to use when page flipping
        /// </summary>
        [Browsable(true)]
        [Category("Page Flip")]
        [Description("The visual effect to use when page flipping")]
        [EditorAttribute(typeof(FlipEffectConfigEditor), typeof(UITypeEditor))]
        public PageFlipEffect PageFlipEffect
        {
            get { return pageFlipEffect; }
            set
            {
                pageFlipEffect = value;
            }
        }

        /// <summary>
        /// Gets or sets the page to flip to when the button is pressed
        /// </summary>
        [Browsable(true)]
        [Category("Page Flip")]
        [Description("The page to flip to when the button is pressed")]            
        [EditorAttribute(typeof(PagePickerEditor), typeof(UITypeEditor))]
        [XmlIgnore]
        public Page PageFlipTarget
        {
            get { return pageFlipTarget; }
            set
            {
                pageFlipTarget = value;
				if (pageFlipEffect != null)
					pageFlipTargetID = pageFlipTarget.ID;
				else
					pageFlipTargetID = 0;
            }
        }

        /// <summary>
        /// Gets or sets the ID of the page to flip to when the button is pressed
        /// </summary>
        [Browsable(false)]
        public ulong PageFlipTargetID
        {
            get { return pageFlipTargetID; }
            set { pageFlipTargetID = value; }
        }

		/// <summary>
		/// Creates a Button instance
		/// </summary>
        public Button()
            : base()
        {
            Dimensions = new Point(100, 50);

            idleImageState.TextureName = DefaultIdleImage;
            idleImageState.TransitionTime = 0.5f;

            focusedImageState.TextureName = DefaultFocusedImage;
            focusedImageState.TransitionTime = 0.5f;

            pressedImageState.TextureName = DefaultPressedImage;
            pressedImageState.TransitionTime = 0.0f;

            textState.FontName = DefaultFont;
            textState.HorizontalJustification = TextHorizontalJustification.Center;
            textState.VerticalJustification = TextVerticalJustification.Center;

            SetImageStates();
            SetTextStates();
        }

        /// <summary>
        /// Initializes the item
        /// </summary>
        /// <param name="parentProject">The parent MenuProject</param>
        /// <param name="contentManager">The ContentManager from which to load content</param>
        /// <param name="graphicsDevice">The GraphicsDevice to use for rendering</param>
        internal override void Initialize(MenuProject parentProject, ContentManager contentManager, GraphicsDevice graphicsDevice)
        {
            base.Initialize(parentProject, contentManager, graphicsDevice);

            if (pageFlipTargetID != 0)
                pageFlipTarget = parentProject.GetMenuItemByID<Page>(pageFlipTargetID);
        }


		/// <summary>
		/// Renders the Button
		/// </summary>
		/// <param name="dt">Time delta</param>
		/// <param name="spriteBatch">The shared SpriteBatch</param>
		/// <param name="lineManager">The shared LineManager</param>
		/// <param name="selected">true if currently selected</param>
		/// <param name="highlighted">true if currently highlighted</param>
        internal override void RenderThis(float dt, SpriteBatch spriteBatch, RoundLineManager lineManager, bool selected, bool highlighted)
        {
            if (DesignMode)
                ImageStateIndex = (int)DesignState;            
            else
            {
                if (Selected)
                    ImageStateIndex = (int)ButtonDesignState.Pressed;
                else if (Focused)
                    ImageStateIndex = (int)ButtonDesignState.Focused;
                else
                    ImageStateIndex = (int)ButtonDesignState.Idle;
            }

            TextStateIndex = 0;

            base.RenderThis(dt, spriteBatch, lineManager, selected, highlighted);            
        }

        /// <summary>
        /// Called when the button is clicked (pressed and depressed while maintaining focus)
        /// </summary>
        protected override void OnClicked()
        {
            base.OnClicked();

            if (pageFlipType != PageFlipType.None)
                GetParentProject().StartPageFlip(pageFlipType, pageFlipEffect, pageFlipTarget);
        }

        /// <summary>
        /// Creates a clone of the item
        /// </summary>
        /// <returns>A clone of the item</returns>
        public override MenuItem Clone()
        {
            Button clone = (Button)base.Clone();

            clone.idleImageState = this.idleImageState.Clone();
            clone.focusedImageState = this.focusedImageState.Clone();
            clone.pressedImageState = this.pressedImageState.Clone();
            clone.SetImageStates();

            clone.textState = this.textState.Clone();
            clone.SetTextStates();

            return clone;
        }

        /// <summary>
        /// Puts all ImageStates in the ImageStates collection
        /// </summary>
        private void SetImageStates()
        {
            ImageStates.Clear();
            ImageStates.Add(idleImageState);
            ImageStates.Add(focusedImageState);
            ImageStates.Add(pressedImageState);
        }

        /// <summary>
        /// Puts all TextStates in the TextStates collection
        /// </summary>
        private void SetTextStates()
        {
            TextStates.Clear();
            TextStates.Add(textState);            
        }        

    }

	/// <summary>
	/// Used to specify the type of PageFlip that occurs when a button is pressed
	/// </summary>
    public enum PageFlipType
    {
        None = 0,
        Page = 1,
        Return = 2
    }

	/// <summary>
	/// Used to indicate which state the button should be in
	/// when in design-mode.
	/// </summary>
    public enum ButtonDesignState
    {
        Idle = 0,
        Focused = 1,
        Pressed = 2
    }
}